#!/bin/zsh
# -*-coding: latin-1;-*-

##########################################################
#
# title:     utility functions
#
# filename:  /etc/zsh/functions/utility
#
# author(s): Alessandro Molari (mola89.molarulez.com),
#            Luca Molari
#
# license:   This file is licensed under the GPLv2
#            For more informations read:
#            http://www.gnu.org/licenses/gpl-2.0.txt
#
# thanks to: zsh team (www.zsh.org)
#            grml team (grml.org)
#            Michael Prokop (mika@grml.org)
#
##########################################################



# add a command line to the shells history without executing it
commit-to-history() {
    print -s ${(z)BUFFER}
    zle send-break
}
zle -N commit-to-history

# only slash should be considered as a word separator
slash-backward-kill-word() {
    local WORDCHARS="${WORDCHARS:s@/@}"
    # zle backward-word
    zle backward-kill-word
}
zle -N slash-backward-kill-word

# actual date in the form yyyy-mm-dd
_bkdatetime() {
    BUFFER="$BUFFER$(date '+%Y.%m.%d-%H.%M.%S')";
    CURSOR=$#BUFFER;
}
zle -N _bkdatetime

echo-datetime() {
    echo `date +%Y.%m.%d-%H.%M.%S`
}

# run command line as user root via sudo:
sudo-command-line() {
    [[ -z $BUFFER ]] && zle up-history
    [[ $BUFFER != sudo\ * ]] && BUFFER="sudo $BUFFER"
}
zle -N sudo-command-line

# jump behind the first word on the cmdline. Useful to add options
function jump_after_first_word() {
    local words
    words=(${(z)BUFFER})

    if (( ${#words} <= 1 )) ; then
        CURSOR=${#BUFFER}
    else
        CURSOR=${#${words[1]}}
    fi
}
zle -N jump_after_first_word

# insert the last typed word again
insert-last-typed-word() {
    zle insert-last-word -- 0 -1
}
zle -N insert-last-typed-word

# create directory and cd to it
mcd() {
    mkdir -p "$@" && cd "$@"
}

# list images only
limg() {
    local -a images
    images=( *.{jpg,gif,png}(.N) )

    if [[ $#images -eq 0 ]] ; then
        print "No image files found"
    else
        la "$images[@]"
    fi
}

# cd to directory and list files
cl() {
    emulate -L zsh
    cd $1 && la
}

# backup file to file_timestamp.bkp
bk() {
    emulate -L zsh
    cp -b $1 $1__bkdatetime.bkp
}

# grep in history
greph() {
    emulate -L zsh
    history 0 | grep $1
}

# find out which libs define a symbol
lcheck() {
    if [[ -n "$1" ]] ; then
        nm -go /usr/lib/lib*.a 2>/dev/null | grep ":[[:xdigit:]]\{8\} . .*$1"
    else
        echo "Usage: lcheck <function>" >&2
    fi
}

# jump between directories
dirjump() {
    emulate -L zsh
    autoload -U colors
    local color=$fg_bold[blue]
    integer i=0
    dirs -p | while read dir; do
        local num="${$(printf "%-4d " $i)/ /.}"
        printf " %s  $color%s$reset_color\n" $num $dir
        (( i++ ))
    done
    integer dir=-1
    read -r 'dir?Jump to directory: ' || return
    (( dir == -1 )) && return
    if (( dir < 0 || dir >= i )); then
        echo d: no such directory stack entry: $dir
        return 1
    fi
    cd ~$dir
}

# print a specific line of file(s)
linenr () {
    emulate -L zsh
    if [ $# -lt 2 ] ; then
       print "Usage: linenr <number>[,<number>] <file>" ; return 1
    elif [ $# -eq 2 ] ; then
         local number=$1
         local file=$2
         command ed -s $file <<< "${number}n"
    else
         local number=$1
         shift
         for file in "$@" ; do
             if [ ! -d $file ] ; then
                echo "${file}:"
                command ed -s $file <<< "${number}n" 2> /dev/null
             else
                continue
             fi
         done | less
    fi
}

# disassemble source files using gcc and as
disassemble(){
    emulate -L zsh
    gcc -pipe -S -o - -O -g $* | as -aldh -o /dev/null
}

# show contents of gzipped tar file
shtar() {
    emulate -L zsh
    gunzip -c $1 | tar -tf - -- | $PAGER
}

# show contents of zip file
shzip() {
    emulate -L zsh
    unzip -l $1 | $PAGER
}

# smart archive extractor
simple-extract () {
    emulate -L zsh
    if [[ -f $1 ]] ; then
        case $1 in
            *.tar.bz2)  bzip2 -v -d $1      ;;
            *.tar.gz)   tar -xvzf $1        ;;
            *.rar)      unrar $1            ;;
            *.deb)      ar -x $1            ;;
            *.bz2)      bzip2 -d $1         ;;
            *.lzh)      lha x $1            ;;
            *.gz)       gunzip -d $1        ;;
            *.tar)      tar -xvf $1         ;;
            *.tgz)      gunzip -d $1        ;;
            *.tbz2)     tar -jxvf $1        ;;
            *.zip)      unzip $1            ;;
            *.Z)        uncompress $1       ;;
            *)          echo "'$1' Error. Please go away" ;;
        esac
    else
        echo "'$1' is not a valid file"
    fi
}

# smart archive creator
smartcompress() {
    emulate -L zsh
    if [[ -n $2 ]] ; then
        case $2 in
            tgz | tar.gz)   tar -zcvf$1.$2 $1 ;;
            tbz2 | tar.bz2) tar -jcvf$1.$2 $1 ;;
            tar.Z)          tar -Zcvf$1.$2 $1 ;;
            tar)            tar -cvf$1.$2  $1 ;;
            gz | gzip)      gzip           $1 ;;
            bz2 | bzip2)    bzip2          $1 ;;
            *)
                echo "Error: $2 is not a valid compression type"
                ;;
        esac
    else
        smartcompress $1 tar.gz
    fi
}

# list an archive's content
show-archive() {
    emulate -L zsh
    if [[ -f $1 ]] ; then
        case $1 in
            *.tar.gz)      gunzip -c $1 | tar -tf - -- ;;
            *.tar)         tar -tf $1 ;;
            *.tgz)         tar -ztf $1 ;;
            *.zip)         unzip -l $1 ;;
            *.bz2)         bzless $1 ;;
            *.deb)         dpkg-deb --fsys-tarfile $1 | tar -tf - -- ;;
            *)             echo "'$1' Error. Please go away" ;;
        esac
    else
        echo "'$1' is not a valid archive"
    fi
}

# bkp file in tar.gz
bkp_compress() {
    emulate -L zsh
    if [[ -e $1 ]]; then
        smartcompress $1 tar.gz
        mv $1.tar.gz "$1_`echo-datetime`.tar.gz"
    fi
}

# clean up directory - remove well known tempfiles
purge() {
    FILES=(*~(N) \
           .*~(N) \
           \#*\#(N) \
           *.o(N) \
           a.out(N) \
           *.core(N) \
           *.cmo(N) \
           *.cmi(N) \
           .*.swp(N) \
           *.pyc(N) \
           *.pyo(N))

    NBFILES=${#FILES}
    if [[ $NBFILES > 0 ]] ; then
        print $FILES
        local ans
        echo -n "Remove these files? [y/n] "
        read -q ans
        if [[ $ans == "y" ]] ; then
            rm ${FILES}
            echo ">> $PWD purged, $NBFILES files removed"
        else
            echo "Ok. .. then not.."
        fi
    fi
}

# create an ISO image
mkiso() {
    emulate -L zsh
    echo " * Volume name "
    read volume
    echo " * ISO Name (ie. tmp.iso)"
    read iso
    echo " * Directory or File"
    read files
    mkisofs -o ~/$iso -A $volume -allow-multidot -J -R -iso-level 3 -V \
        $volume -R $files
}

# convert numbers base
baseconv() {
    if [ $# -eq 3 ]; then
        echo "obase=$2; ibase=$1; $3"|bc
    else
        echo "Invalid parameters.\nOnly 3 parameters are needed:\n\t1- InputBase\n\t2- OutputBase\n\t3- InputNumber"
    fi
}

# compile and (maybe) execute java code
jce() {
    if [ $# -eq 1 ]; then
        local strlength=${#1}
        local execstrlength=$(($strlength - 5))
        local execstr=${1[1,$execstrlength]}
        javac $1
        local retcode=$?
        if [ $retcode -eq 0 ]; then
            java $execstr
            local retcode=$?
        else
            echo "Compiling exit code "$retcode": "$execstr" not executed"
            return $retcode
        fi
    else
        echo "Too many arguments. Only one is needed"
        return 1
    fi
}
